package sge.Datos;

import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Victor Cifuentes
 * @version 0.9.7
 * @since
 */
abstract class Conexion {

    private Connection con;
    private Statement stm;
    protected ResultSet rs;
    private ResultSetMetaData rsmd;
    //private DatabaseMetaData dbmt;
    protected String url_link;
    protected String URL = "";
    protected String dbName = "";
    protected String extend = "";
    protected String user = "";
    protected String password = "";

    protected abstract void crearUsuario();

    protected abstract void crearBaseDatos();

    public abstract boolean existeBaseDatos(String nbd);

    public abstract void conectarConBaseDatos(String dbName);

    protected abstract void errorDeConexion(SQLException e);

    private void Conexion() {
    }

    protected void conectar() {
        try {
            if (con != null) {
                cerrarConexion();
            }
            con = DriverManager.getConnection(URL + dbName + extend, user, password);
            stm = con.createStatement();
            crearBaseDatos();
            crearUsuario();

            //dbmt = con.getMetaData();
        } catch (SQLException e) {
            errorDeConexion(e);
        }
    }

    public boolean activa() {
        boolean connected = false;
        try {
            connected = con != null && con.isValid(500);
        } catch (SQLException ex) {
            Logger.getLogger(Conexion.class.getName()).log(Level.SEVERE,
                    null, ex);
        }
        return connected;
    }

    public Statement crearSentencia() throws SQLException {

        return con.createStatement();

    }

    public PreparedStatement crearSentenciaPreparada(String sql) {
        PreparedStatement ps = null;
        try {
            ps = con.prepareStatement(sql);
        } catch (SQLException ex) {
            Logger.getLogger(Conexion.class.getName()).log(
                    Level.SEVERE, "No se pudo ejecutar la expresión: \n"
                    + sql + "\n", ex);
        }
        return ps;
    }

    public int ejecutarSQL(String sql) {
        int nreg = 0;
        try {
            nreg = stm.executeUpdate(sql);
        } catch (SQLException ex) {
            Logger.getLogger(Conexion.class.getName()).log(
                    Level.SEVERE, "No se pudo ejecutar la expresión: \n"
                    + sql + "\n", ex);
        }
        return nreg;
    }

    public void consultar(String sql) {
        try {
            rs = stm.executeQuery(sql);
            rsmd = rs.getMetaData();
        } catch (SQLException ex) {
            Logger.getLogger(Conexion.class.getName()).log(
                    Level.SEVERE, "No se pudo ejecutar la expresión: \n"
                    + sql + "\n", ex);
        }
    }

    public boolean ejecutarArchivo(URL origen) throws IOException {
        boolean nreg = false;
        try {
            byte[] encoded = Files.readAllBytes(Paths.get(origen.toURI()));
            String sql = Charset.defaultCharset().decode(ByteBuffer.wrap(encoded)).toString();
            nreg = stm.execute(sql);
        } catch (SQLException | URISyntaxException ex) {
            Logger.getLogger(Conexion.class.getName()).log(
                    Level.SEVERE, "No se pudo ejecutar el archivo: "
                    + origen + "\n", ex);
        }
        return nreg;
    }

    public boolean ejecutar(String sql) {
        boolean reg = false;
        try {
            reg = stm.execute(sql);
        } catch (SQLException ex) {
            Logger.getLogger(Conexion.class.getName()).log(
                    Level.SEVERE, "No se pudo ejecutar la expresión: \n"
                    + sql + "\n", ex);
        }
        return reg;
    }

    public Integer obtenerUltimoIDGenerado() {

        try {
            rs = stm.executeQuery("SELECT LAST_INSERT_ID()");
            if (rs.next()) {
                return rs.getInt(1);
            }

        } catch (SQLException ex) {
            Logger.getLogger(Conexion.class.getName()).log(
                    Level.SEVERE, "No fue posible recupear ID asignado", ex);
        }
        return new Integer(-1);
    }

    protected void cerrarConexion() {
        try {
            cerrarSentencia();
            if (con != null) {
                con.close();
            }
        } catch (SQLException ex) {
            Logger.getLogger(Conexion.class.getName()).log(Level.SEVERE,
                    "No se pudo cerrar la conexión con la base de datos.", ex);
        }
    }

    protected void cerrarSentencia() {
        try {
            cerrarResultados();
            if (stm != null) {
                stm.close();
            }
        } catch (SQLException ex) {
            Logger.getLogger(Conexion.class.getName()).log(Level.SEVERE,
                    "No se pudo cerrar el ejecutor de expresiones.", ex);
        }
    }

    public void cerrarResultados() {
        try {
            if (rs != null) {
                rs.close();
            }
        } catch (SQLException ex) {
            Logger.getLogger(Conexion.class.getName()).log(Level.SEVERE,
                    "No se pudo cerrar el resultado de la consulta.", ex);
        }
    }

    public void refrescarTablas() {
        ejecutar("FLUSH TABLES");
    }

//    @Override
//    public Conexion clone() {
//        Conexion clone = new MySQL(dbName);
//
//        clone.setConexion(con);
//        clone.createStatement();
//
//        return clone;
//    }
    public void setConexion(Connection con) {
        this.con = con;
    }

    public void setStatement(Statement stm) {
        this.stm = stm;
    }

    public Connection getConexion() {
        return con;
    }

    /*public DatabaseMetaData getDbMetaData() {
     return dbmt;
     }*/
    public Statement getStatement() {
        return stm;
    }

    public ResultSet getResultSet() {
        return rs;
    }

    public ResultSetMetaData getResultSetMetaData() {
        return rsmd;
    }

    public String getURL() {
        return URL;
    }

    public String getDataBaseName() {
        return dbName;
    }

    public void setNombreConexion(String NombreConexion) {
        this.dbName = NombreConexion;
    }

    public String getUsuario() {
        return user;
    }

    public void setUsuario(String Usuario) {
        this.user = Usuario;
    }

    public String getClave() {
        return password;
    }

    public void setClave(String Clave) {
        this.password = Clave;
    }
}
